#include "GapStateRegistered.h"
#include "GapStateMap.h"
#include "GAP.pb.h"
#include "Trace.h"
#include "MediaLibrary.h"
#include "MediaConnectionsHandler.h"
#include "SgwGapProxy.h"

namespace tsc
{
namespace mgw
{

using namespace GatewayApplicationPart;
using namespace tsc::common;

/*******************************************************************************
 *
 * Constructor
 *
 ******************************************************************************/
GapStateRegistered::GapStateRegistered() :
	GapStateBase("Registered")
{

} // GapStateRegistered::GapStateRegistered

/*******************************************************************************
 *
 * Destructor
 *
 ******************************************************************************/
GapStateRegistered::~GapStateRegistered()
{

} // GapStateRegistered::~GapStateRegistered

//===================================================================
GapStateRegistered* GapStateRegistered::instance()
{
	static GapStateRegistered mInstance;
	return &mInstance;
}

//===================================================================
void
GapStateRegistered::handleEventGapEchoReq(
    GapGenerator* gapGen,
    GapEventEchoReq* event,
    EventData*& eventData)
{
    TRACE(3, "Received GapEchoRequest");

    if(!SgwGapProxy::instance().sendGapEchoResp(*gapGen))
    {
        TRACE(1, "Failed to send GapEchoResp");
        // XXX consider this as link break situation ??
        // and change state to UNREGISTERED to try to establish
        // connection again?
    }
    TRACE(3, "GapEchoResponse sent");

    EventData::deleteEvent(eventData);
}

//===================================================================
void
GapStateRegistered::handleEventGapMediaBearerSetupReq(
    GapGenerator* gapGen,
    GapEventMediaBearerSetupReq* event,
    EventData*& eventData)
{
    TRACE(6,
      STR("Received MediaBearerSetupReq, connId=0x%x, clientIp=%s, "
          "clientPort=%u, mediaItemId=%u",
          event->getConnectionId(),
          event->getClientAddress()->DebugString().c_str(),
          event->getClientMediaPort(),
          event->getMediaItemId()));

    if(!MediaLibrary::instance().itemExists(event->getMediaItemId()))
    {
        TRACE(1,
          STR("Media item with ID=%u does not exist - "
              "rejecting media bearer setup",
              event->getMediaItemId()));

        if(!SgwGapProxy::instance().sendGapMediaBearerSetupRej(
                *gapGen,
                event->getConnectionId(),
                GatewayApplicationPart::CAUSE_UNSPECIFIED))
        {
            TRACE(1,
              STR("Failed to send GapMediaBearerSetupRej, connId=0x%x",
                  event->getConnectionId()));
        }
        EventData::deleteEvent(eventData);
        return;
    }

    MediaGenerator* g = 0;
    if(MediaConnectionsHandler::instance().
            findConnection(event->getConnectionId(), g))
    {
        TRACE(1,
          STR("MediaConnection with id=0x%x is already established - rejecting",
              event->getConnectionId()));

        if(!SgwGapProxy::instance().sendGapMediaBearerSetupRej(
                *gapGen,
                event->getConnectionId(),
                GatewayApplicationPart::CAUSE_MEDIA_CONNECTION_ALREADY_EXISTS))
        {
            TRACE(1,
              STR("Failed to send GapMediaBearerSetupRej, connId=0x%x",
                  event->getConnectionId()));
        }
        EventData::deleteEvent(eventData);
        return;
    }

    if(MediaConnectionsHandler::instance().
            setupConnection(g,
                            event->getConnectionId(),
                            event->getClientAddress(),
                            event->getClientMediaPort(),
                            event->getMediaItemId()))
    {
        TRACE(3,
          STR("MediaConnection with id=0x%x has been set up - sending CFM",
              event->getConnectionId()));

        if(!SgwGapProxy::instance().sendGapMediaBearerSetupCfm(
                *gapGen,
                event->getConnectionId(),
                g->getServerMediaPort()))
        {
            TRACE(1,
              STR("Failed to send GapMediaBearerSetupCfm, connId=0x%x",
                  event->getConnectionId()));

            // tear down the connection
            MediaConnectionsHandler::instance().
                releaseConnection(event->getConnectionId());
        }
    }
    else
    {   // media connection setup failed => send reject
        if(!SgwGapProxy::instance().sendGapMediaBearerSetupRej(
                *gapGen,
                event->getConnectionId(),
                GatewayApplicationPart::CAUSE_UNSPECIFIED))
        {
            TRACE(1,
              STR("Failed to send GapMediaBearerSetupRej, connId=0x%x",
                  event->getConnectionId()));
        }
        else
        {
            TRACE(3,
              STR("GapMediaBearerSetupRej for id=0x%x, with cause=%u has been sent",
                   event->getConnectionId(),
                   GatewayApplicationPart::CAUSE_UNSPECIFIED));
        }
    }

    EventData::deleteEvent(eventData);
}

//===================================================================
void
GapStateRegistered::handleEventGapMediaBearerRelease(
    GapGenerator* gapGen,
    GapEventMediaBearerRelease* event,
    EventData*& eventData)
{
    TRACE(6, STR("Received MediaBearerRelease, connId=0x%x",
                 event->getConnectionId()));

    if(MediaConnectionsHandler::instance().
            releaseConnection(event->getConnectionId()))
    {
        TRACE(3, STR("Connection with connId=0x%x - released",
                     event->getConnectionId()));
    }
    else
    {
        TRACE(1, STR("Failed to release connection with connId=0x%x",
                     event->getConnectionId()));
    }

    EventData::deleteEvent(eventData);
}


} // namespace mgw
} // namespace tsc
